<template>
  <n-form
    ref="solutionFormRef"
    label-placement="left"
    label-align="right"
    label-width="80px"
    :show-require-mark="false"
    class="h-full flex-col flex-1 rounded-5 bg-white p-10 dark:bg-dark"
  >
    <div class="mb-10 flex justify-between">
      <n-flex>
        <n-form-item :show-feedback="false" class="mr-20 w-130">
          <n-select
            :value="language"
            placeholder="选择编程语言"
            :options="langOptions || []"
            @update:value="handleLangValue"
          />
        </n-form-item>
        <n-form-item :show-feedback="false" class="mr-20 w-130">
          <n-select
            :value="compiler"
            placeholder="选择编译器"
            :options="compOptions || []"
            @update:value="handleCompValue"
          />
        </n-form-item>
      </n-flex>
      <div class="f-c-c">
        <CopyButton :text="sourceCode" pop-msg="复制代码" placement="left" />
      </div>
    </div>
    <div class="flex-1 overflow-auto">
      <Codemirror
        v-model="sourceCode"
        :extensions="extensions"
        :autofocus="true"
        :disabled="false"
        :tab-size="4"
      />
    </div>
    <div class="mt-12 flex items-end gap-10">
      <n-button type="primary" :disabled="frozenPeriod > 0" @click="onSolutionSubmit">
        {{ frozenPeriod > 0 ? `${frozenPeriod}秒后可以提交` : '提交代码' }}
      </n-button>
      <n-button :loading="explainLoading" :disabled="chatDisabled" @click="explainCode">
        解释代码
      </n-button>
      <n-button :loading="fixLoading" :disabled="chatDisabled" @click="fixCode">修复代码</n-button>
      <n-button :loading="optimizeLoading" :disabled="chatDisabled" @click="optimizeCode">
        优化代码
      </n-button>
    </div>
  </n-form>
  <n-modal
    v-model:show="showChatResModal"
    :mask-closable="false"
    size="large"
    type="success"
    preset="card"
    title="结果"
    class="h-500 max-w-600"
    style="position: fixed; left: 20px; top: 80px"
  >
    <n-input
      v-model:value="analyzedCode"
      type="textarea"
      rows="10"
      placeholder="分析结果"
      readonly
      class="h-full"
    />
    <template #footer>
      <p class="text-gray-500">关闭后若不修改代码会暂时保存结果，无需再次请求。</p>
    </template>
  </n-modal>
</template>

<script setup>
import { lStorage } from '@/utils'
import { Codemirror } from 'vue-codemirror'
import { cpp } from '@codemirror/lang-cpp' // C/C++ 代码高亮
import { java } from '@codemirror/lang-java' // Java 代码高亮
import { python } from '@codemirror/lang-python' // Python 代码高亮
import api from '@/api/user'
import sha256 from 'crypto-js/sha256'

const exam = inject('problem/exam')
const sourceCode = inject('problem/sourceCode')
const language = inject('problem/language')
const compiler = inject('problem/compiler')

const submitCodeByIdApi = inject('problem/submitCodeByIdApi')

const frozenPeriod = ref(0) // 提交冷冻期
const codeSubmitTimer = ref(null) // 定时器

const languages = ref([])
const compilers = ref(['MinGW', 'MSVC', 'JDK8', 'Python'])

// 大模型相关
const showChatResModal = ref(false)
const chatDisabled = ref(false)
const explainLoading = ref(false)
const fixLoading = ref(false)
const optimizeLoading = ref(false)
const analyzedCode = ref('')
const analyzedCodeMap = new Map()

const langOptions = computed(() => {
  console.log(languages.value)
  let options = languages.value.map((l) => ({
    label: l,
    value: l,
  }))
  if (options.length === 1) {
    language.value = options[0].value
  }
  return options
})

const compOptions = computed(() => {
  let options
  // 判断当前选定的编程语言并根据此调整可用的编译器选项
  if (language.value === 'C' || language.value === 'C++') {
    options = ['MinGW', 'MSVC'].map((comp) => ({ label: comp, value: comp }))
  } else if (language.value === 'Java') {
    options = [{ label: 'JDK8', value: 'JDK8' }]
  } else if (language.value === 'Python') {
    options = [{ label: 'Python 3.12', value: 'Python 3.12' }]
  } else {
    options = []
  }

  // 如果编译器选项只有一个，则自动选择该选项
  if (options.length === 1) {
    compiler.value = options[0].value
  }
  // 若当前选定的编译器不在新的选项列表中，重置选定的编译器
  else if (!options.some((option) => option.value === compiler.value)) {
    compiler.value = null
  }

  return options
})
const extensions = computed(() => {
  return [...codeHilight(language.value)]
})

// 代码高亮的语言
const codeHilight = (language) => {
  if (language === 'C' || language === 'C++') {
    return [cpp()]
  } else if (language === 'Java') {
    return [java()]
  } else if (language === 'Python') {
    // 添加对 Python 的支持
    return [python()]
  }
  return []
}

const handleLangValue = (val) => {
  language.value = val
}
const handleCompValue = (val) => {
  compiler.value = val
}
// 提交代码
const onSolutionSubmit = async () => {
  if (frozenPeriod.value > 0) return
  if (!language.value) {
    $message.error('编程语言不能为空')
    return
  }
  if (!compiler.value) {
    $message.error('编译器不能为空')
    return
  }
  if (sourceCode.value.trim() === '') {
    $message.error('代码不能为空')
    return
  }

  // 提交冷冻期
  frozenPeriod.value = 10
  if (codeSubmitTimer.value) {
    clearInterval(codeSubmitTimer.value)
    codeSubmitTimer.value = null
  }
  codeSubmitTimer.value = setInterval(() => {
    frozenPeriod.value--
    if (frozenPeriod.value <= 0 && codeSubmitTimer.value) {
      clearInterval(codeSubmitTimer.value)
    }
  }, 1000)

  // 提交代码
  try {
    await submitCodeByIdApi(language.value, sourceCode.value, compiler.value)
    $message.success('提交成功')
  } catch (err) {
    console.log(err)
  }
}

// 大模型相关
const chatWithLLM = async (text, instruction, maxLength = 2048) => {
  try {
    const key = sha256(instruction + text).toString()
    if (analyzedCodeMap.has(key)) {
      analyzedCode.value = analyzedCodeMap.get(key)
      showChatResModal.value = true
      return
    }
    chatDisabled.value = true
    if (text.length > maxLength) {
      $message.error(`代码过长！`)
      return
    }
    const res = await api.chatWithLLM({
      text,
      maxLength,
    })
    analyzedCode.value = res.data
      .replace(/^"|"$/g, '')
      .replace(/\\\\n/g, '{{TEMP_NEWLINE}}')
      .replace(/\\n/g, '\n')
      .replace(/{{TEMP_NEWLINE}}/g, '\\n')
      .replace(/\\t/g, '\t')
      .replace(/\\"/g, '"')
    if (res.data) {
      showChatResModal.value = true
      analyzedCodeMap.set(sha256(instruction + text).toString(), analyzedCode.value)
    }
  } catch (err) {
    console.log(err)
  } finally {
    chatDisabled.value = false
    explainLoading.value = false
    fixLoading.value = false
    optimizeLoading.value = false
  }
}

// 解释代码
const explainCode = () => {
  explainLoading.value = true
  const prompt = '请详细描述以下代码的功能\n'
  chatWithLLM(prompt + sourceCode.value, 'explain')
}

// 修复代码
const fixCode = () => {
  fixLoading.value = true
  const prompt = '请分析一下代码，更改其中的错误\n'
  chatWithLLM(prompt + sourceCode.value, 'fix')
}

// 优化代码
const optimizeCode = () => {
  optimizeLoading.value = true
  const prompt = '请重构以下代码，确保新代码可以获得性能提升或者结构简洁\n'
  chatWithLLM(prompt + sourceCode.value, 'optimize')
}

//生命周期
watch(exam, (newExam) => {
  languages.value = newExam?.language.split(',') || []
  console.log(newExam?.language)
})
watch(compiler, (newCompiler) => {
  // 存12小时
  lStorage.set('code-compiler', newCompiler, 12 * 60 * 60)
})
onMounted(() => {
  const storedCompiler = lStorage.get('code-compiler')
  if (compilers.value.includes(storedCompiler)) {
    compiler.value = storedCompiler
  }
})
watch(language, (newLanguage) => {
  // 存12小时
  lStorage.set('code-language', newLanguage, 12 * 60 * 60)
})
watch(languages, (newLanguages) => {
  if (!newLanguages) return
  if (newLanguages.length === 1) {
    handleLangValue(newLanguages[0])
  } else if (newLanguages.length > 1) {
    const storedLang = lStorage.get('code-language')
    if (newLanguages.includes(storedLang)) {
      handleLangValue(storedLang)
    }
  }
})

onBeforeUnmount(() => {
  if (codeSubmitTimer.value) {
    clearInterval(codeSubmitTimer.value)
    codeSubmitTimer.value = null
  }
})
</script>
